<?php
/**
 * @file Db.php
 *
 * Database representation.
 *
 * With this class you can interact with the databases. It uses by default the
 * connection in configuration.php for establishing a connection.
 *
 * New BSD License
 * \n
 * Copyright (c) 2010 Rpd-Team
 */

/**
 * Connection to a Database
 * @since  0.0.9
 *
 * This class represent a connection to a database and can send queries to it.
 *
 *
 * @section Changelog
 *
 * <table>
 * 	<tr>
 * 		<th>Version</th>
 * 		<th>Description</th>
 *  </tr>
 *  <tr><td>0.1.0</td><td>insert_id() returns the last inserted ID</td></tr>
 * </table>
 *
 *
 * @section Examples
 *
 *
 * @see Model
 *
 */
	class Db implements Db_Interface {
	protected $_sql;
	
	function connectionClose()
	{
		$this->_sql->closeConnection();
	}
	
	function connectionIsActive()
	{
		return $this->_sql->connectionIsActive();
	}

	function database($name)
	{
		$this->_sql->database($name);
	}
	
	function encoding($charset)
	{
		$this->_sql->encoding($charset);
	}
	
	public function getLink()
	{
		return $this->_sql->getLinkId();
	}

	/**
	 * Last inserted ID
	 *
	 * After running an insert this function gives you the last generated ID.
	 *
	 * @since 0.2.0
	 *
	 * @return integer Last generated ID
	 *
	 * @section Changelog
	 *
	 * <table>
	 * 	<tr>
	 * 		<th>Version</th>
	 * 		<th>Description</th>
	 *  </tr>
	 *  <tr><td></td><td></td></tr>
	 * </table>
	 *
	 * @section Examples
	 *
	 * @subsection Db_query_insert_id Get last inserted ID
	 *
	 * <pre>/app/Controller/index.php</pre>
	 * @code
	 * <?php
	 *
	 * // connect to database
	 * $db = new Db();
	 *
	 * // run some insert
	 * $db->query("INSERT INTO some_table (some_field) VALUES (123)");
	 *
	 * // show ID that has been generated in the table
	 * echo $db->lastInsertId();
	 *
	 * ?>
	 * @endcode
	 *
	 * <pre>Output "/"</pre> (will be the according ID)
	 *
	 * @see Db::query
	 */
	function lastInsertId()
	{
		return $this->_sql->lastInsertId();
	}
	
	/**
	 * @deprecated 0.3.0
	 */
	function insert_id()
	{
		return $this->lastInsertId();
	}
	
	/*
	 * Set up a statement with placeholders
	 *
	 * Some databases can prepare queries to enhance security and performance
	 * of your queries. Thats because you seperate the SQL logic from the data
	 * being supplied and let the server parse the statement only one time.
	 * 
	 * Currently supported
	 * <i title="Relational database management system">RDBMS</i>
	 * are (\ref Configuration "see \"Database configuration\""):
	 *  - MySQL
	 *
	 * @since 0.2.0
	 *
	 * @return \c Db_Prepared Prepared statement class
	 *
	 * @section Examples
	 * 
	 * @subsection Prepare SQL statement with wildcard parameters
	 * @code
	 * <?php
	 * $db = new Db();	// get connection to database
	 * 
	 * // prepare an often used statement
	 * $prepared = $db->prepare("SELECT name
	 *                           FROM food
	 *                           WHERE type = ?
	 *                             AND calories < ?
	 *                          ");
	 *
	 * // fetch some results
	 * $result = $prepared( array("meat", 200000) );
	 * 
	 * // now $result contains a Db_Statement which you can use as common
	 * foreach ($result as $meal)
	 * {
	 * 	echo "Eat $meal! ";
	 * }
	 * ?>
	 * @endcode
	 * \nomagic{ Db_Prepared::pipe will get the same result:,
	 *           $result = $prepared->pipe( array("meat"\, 200000) );
	 * }
	 * 
	 
	function prepare($statement)
	{
		return $this->_sql->prepare();
	}
	*/
	
	/**
	 * Alias of Db::__invoke()
	 * @copydoc Db::__invoke()
	 */
	public function pipe($in)
	{
		$this->__invoke($in);
	}
	
	public function prepare($statement)
	{
		return $this->_sql->prepare($statement);
	}

	/**
	 * Executes a query
	 * @since 0.0.1
	 *
	 * @param string $statement A SQL-Query
	 * @param string $escape1 Text to escape
	 * @param string $escape2 ...
	 *
	 * @return An iterateable Db_Statement
	 *
	 * @section Changelog
	 *
	 * <table>
	 * 	<tr>
	 * 		<th>Version</th>
	 * 		<th>Description</th>
	 *  </tr>
	 *  <tr><td>0.0.9</td><td>Able to escape incoming values</td></tr>
	 * </table>
	 *
	 * @section Examples
	 *
	 * @subsection Db_query-easy_query Run query
	 *
	 * <pre>/app/Controller/index.php</pre>
	 * @code
	 * <?php
	 *
	 * // make new instance
	 * $db = new Db();
	 *
	 * // run some query
	 * $statement = $db->query("SELECT * FROM some_table");
	 *
	 * ?>
	 * @endcode
	 *
	 *
	 * @subsection Db_query-Escape Escape characters
	 *
	 * Consider the topic "SQL Injections". Some users try to harm your site
	 * with SQL statements within your forms. This will cause the system to
	 * show them every information they want as long as you don't escape them.
	 *
	 * <pre>/app/Controller/index.php</pre>
	 * @code
	 * <?php
	 *
	 * $sensitive = "' || '' = '";
	 *
	 * // make new instance
	 * $db = new Db();
	 *
	 * // run query with escaped chars
	 * $statement = $db->query("SELECT * FROM users WHERE name = '%s'",
	 *                          $sensitive);
	 *
	 * ?>
	 * @endcode
	 *
	 * @see Db::__construct()
	 * @see Db_Statement
	 * 
	 * @todo D1104 eat objects (store objects serialized in db)
	 * @todo A1103 quote see Db::quote
	 */
	function query($statement)
	{
		/**
		 * @todo D110103 multi-line statement seperated by ";[\s*[^"]]" 23.10.2010
		 */
		if (func_num_args() > 1)
		{
			$a = func_get_args();
			array_shift($a);
			return $this->_sql->query($statement, $a);
		}

		return $this->_sql->query($statement);
	}
	
	/**
	 * Escape chars for clean statement
	 *
	 * To enhance the security of your site it's common to verify all data
	 * that has been send by the client (or user / visitor). For SQL statement
	 * and prevent SQL-Injections you have Db::query and the here shown
	 * Db::quote.
	 * 
	 * @todo quote better (divide by scalar, non-scalar, numbers and strings)
	 * 
	 * @since 0.2.0
	 *
	 * @return \c mixed Escaped chars
	 * 
	 * @todo make command for types and relevant manual page (like \T_mixed)
	 *
	 * @section Examples
	 * 
	 * @subsection Db-quote_Escaping Escaping sensitive data for query
	 * @code
	 * <?php
	 * // get connection to database
	 * $db = new Db();
	 * 
	 * // escape to prevent attacks
	 * $name = $db->quote($_POST["name"]);
	 * 
	 * // use for statement
	 * $db->query("SELECT * FROM food WHERE name = $name");
	 * ?>
	 * @endcode
	 * \magic{ Db::query could have done this easier,
	 *         $db->query("SELECT * FROM food name = ?"\, $_POST["name"]);
	 * }
	 * @todo escape whole arrays
	 * 
	 * @see Db::prepare
	 * @see Db::query
	 * 
	 */
	function quote($unescaped_string)
	{
		return $this->_sql->quote($unescaped_string);
	}
	
	/**
	 * Begins a transaction in database
	 * 
	 * @since 0.2.0
	 * 
	 * @section Examples
	 * 
	 * @subsection Db_transactionBegin Begin a new transaction
	 * @code
	 * 
	 * // get connection to database
	 * $db = new Db();
	 * 
	 * // begin normal transaction
	 * $db->transactionBegin();
	 *  
	 * // tell what to do
	 * $db->query("TRUNCATE some_table");
	 * $db->query("UPDATE another_table SET x = 1");
	 *  
	 * // do it
	 * $db->transactionCommit();
	 * @endcode
	 * 
	 * @see Db::transactionCommit
	 * @see Db::transactionIsActive
	 * @see Db::transactionRollback
	 */
	function transactionBegin()
	{
		return $this->_sql->transactionBegin();
	}
	
	/**
	 * Runs a prepared transaction
	 * 
	 * @since 0.2.0
	 * 
	 * @section Examples
	 * 
	 * @subsection Db_transactionCommit Begin a new transaction
	 * @code
	 * 
	 * // get connection to database
	 * $db = new Db();
	 * 
	 * // begin normal transaction
	 * $db->transactionBegin();
	 *  
	 * // tell what to do
	 * $db->query("TRUNCATE some_table");
	 * $db->query("UPDATE another_table SET x = 1");
	 *  
	 * // do it
	 * $db->transactionCommit();
	 * @endcode
	 * 
	 * @see Db::transactionCommit
	 * @see Db::transactionIsActive
	 * @see Db::transactionRollback
	 */
	function transactionCommit()
	{
		return $this->_sql->transactionCommit();
	}
	
	/**
	 * Shows state of transaction
	 * 
	 * @since 0.2.0
	 * 
	 * @return boolean
	 * 
	 * @section Examples
	 * 
	 * @subsection Db_transactionIsActive Check current state of transaction
	 * @code
	 * 
	 * // get connection to database
	 * $db = new Db();
	 * 
	 * // only begin new transaction if none is running
	 * if ($db->transactionIsActive == false)
	 * {
	 * 	$db->transactionBegin();
	 * }
	 * @endcode
	 * 
	 * @see Db::transactionCommit
	 * @see Db::transactionIsActive
	 * @see Db::transactionRollback
	 */
	function transactionIsActive()
	{
		return $this->_sql->transactionIsActive();
	}
	
	/**
	 * Skips current transaction
	 * 
	 * @since 0.2.0
	 * 
	 * @section Examples
	 * 
	 * @subsection Db_transactionRollback Skip a transaction
	 * @code
	 * 
	 * // get connection to database
	 * $db = new Db();
	 * 
	 * // begin normal transaction
	 * $db->transactionBegin();
	 *  
	 * // tell what to do
	 * $db->query("TRUNCATE some_table");
	 * $db->query("UPDATE another_table SET x = 1");
	 *  
	 * // in case of some mistake: don't do it!
	 * $db->transactionRollback();
	 * @endcode
	 * 
	 * @see Db::transactionBegin
	 * @see Db::transactionCommit
	 * @see Db::transactionIsActive
	 */
	function transactionRollback()
	{
		return $this->_sql->transactionRollback();
	}

	/**
	 * Constructor for new Db instance
	 * @since 0.0.1
	 * @param string $settings Connection settings
	 * @return Nothing except an instance of Db when used with "new Db();"
	 *
	 * @section Changelog
	 *
	 *  <table>
	 * 	<tr>
	 * 		<th>Version</th>
	 * 		<th>Description</th>
	 *  </tr>
	 *  <tr><td></td><td></td></tr>
	 * </table>
	 *
	 * @section Examples
	 *
	 * @subsection Db_Config Connect using configuration
	 *
	 * <pre>/configuration.php</pre>
	 * @verbatim [db/std]
 server     = 127.0.0.1      ; address to your server
 user       = some_username
 password   = some_password
 database   = some_database
 driver     = mysql          ; server runs on ...
 persistent = 0              ; keep persistent connections? (0=no, 1=yes)
 encoding   = UTF-8 @endverbatim
	 *
	 * <pre>/app/Controller/index.php</pre>
	 * @code
	 * <?php
	 *
	 * $db = new Db();		// uses "db/std" by default
	 *
	 * // use another configuration
	 * $db = new Db(Registry::get("db/std"));
	 *
	 * ?>
	 * @endcode
	 *
	 * @subsection Db_Array Manually connect
	 * <pre>/app/Controller/index.php</pre>
	 * @code
	 * <?php
	 *
	 * $settings = array(
	 *   "server"     => "127.0.0.1",
	 *   "user"       => "some_username",
	 *   "password"   => "some_password",
	 *   "database"   => "some_database",
	 *   "driver"     => "mysql",
	 *   "persistent" => 0,
	 *   "encoding"   => "UTF-8"
	 * );
	 *
	 * $db = new Db($settings);
	 *
	 * ?>
	 * @endcode
	 */
	function __construct($settings = NULL)
	{
		/**
		 * @todo B110328 eat already established links instead of settings
		 */
		if ($settings === NULL)
		{
			$settings = Registry::get("db/std");
		}

		$class = "Db_Adapter_" . strtolower($settings["driver"]);

		if (class_exists($class))
		{
			$this->_sql = new $class($settings);
			$this->_sql->database($settings["database"]);
			$this->_sql->encoding($settings["encoding"]);
		}
		else
		{
			throw new Error("Unknown driver " . $settings["driver"]);
		}
	}
}

?>